from typing import List, Self, Tuple, Sequence, overload
import pygame

CoordinateType = Tuple[int, int] | Sequence[int] | pygame.Vector2

class Coordinate:
        
    @overload
    def __init__(self, __x: float, __y: float): ...
    @overload
    def __init__(self, __coordinate: CoordinateType): ...
    @overload
    def __init__(self, __coordinate: Self): ...
    def __init__(self, *args):
        if len(args) == 2:
            self.coordinate = pygame.Vector2(args[0], args[1])
        elif isinstance(args[0], self.__class__):
            self.coordinate = pygame.Vector2(args[0].Vector2)
        else:
            self.coordinate = pygame.Vector2(args[0])
            
    @property
    def x(self) -> float:
        return self.coordinate.x
    
    @x.setter
    def x(self, value: float):
        self.coordinate.x = value
        
    @property
    def y(self) -> float:
        return self.coordinate.y
    
    @y.setter
    def y(self, value: float):
        self.coordinate.y = value
        
    @property
    def Vector2(self) -> pygame.Vector2:
        return self.coordinate
        
    @overload
    def __add__(self, other: Self) -> Self: ...
    @overload
    def __add__(self, other: pygame.Vector2) -> Self: ...
    def __add__(self, other: Self | pygame.Vector2) -> Self:
        if isinstance(other, pygame.Vector2):
            return self.__class__(self.coordinate + other)
            
        return self.__class__(
            self.x + other.x,
            self.y + other.y
        )
    
    @overload
    def __sub__(self, other: Self) -> Self: ...
    @overload
    def __sub__(self, other: pygame.Vector2) -> Self: ...
    def __sub__(self, other: Self | pygame.Vector2) -> Self:
        if isinstance(other, pygame.Vector2):
            return self.__class__(self.coordinate - other)
            
        return self.__class__(
            self.x - other.x,
            self.y - other.y
        )
        
    def __str__(self) -> str:
        return f"({self.x}, {self.y})"
    
    @overload        
    def getDistance(self, other: CoordinateType) -> float: ...
    @overload
    def getDistance(self, other: Self) -> float: ...
    def getDistance(self, other: CoordinateType | Self) -> float:
        if not isinstance(other, self.__class__):
            coord = self.__class__(other)
        else:
            coord = other
        
        return pow(
            abs(self.x - coord.x) ** 2 + abs(self.y - coord.y) ** 2,
            0.5
        )
